diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 7ee598c64c2..dbe8bab5c8a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -387,6 +387,10 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty return this is ConeStubType // TODO: distinguish stub types for builder inference and for subtyping } + override fun SimpleTypeMarker.isStubTypeForBuilderInference(): Boolean { + return this is ConeStubType // TODO: distinguish stub types for builder inference and for subtyping + } + override fun intersectTypes(types: List): SimpleTypeMarker { @Suppress("UNCHECKED_CAST") return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List) as SimpleTypeMarker diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index 1d26021fe55..1c6f29a0af8 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -53,6 +53,8 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon override fun SimpleTypeMarker.isStubTypeForVariableInSubtyping() = false + override fun SimpleTypeMarker.isStubTypeForBuilderInference() = false + override fun FlexibleTypeMarker.asDynamicType() = this as? IrDynamicType override fun FlexibleTypeMarker.asRawType(): RawTypeMarker? = null diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt index f1ba7f38293..929f95112e1 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt @@ -97,6 +97,10 @@ object NewCommonSuperTypeCalculator { commonSuperType } + private fun TypeSystemCommonSuperTypesContext.isCapturedStubTypeForVariableInSubtyping(type: SimpleTypeMarker) = + type.asCapturedType()?.typeConstructor()?.projection()?.takeUnless { it.isStarProjection() } + ?.getType()?.asSimpleType()?.isStubTypeForVariableInSubtyping() == true + private fun TypeSystemCommonSuperTypesContext.refineNullabilityForUndefinedNullability( types: List, commonSuperType: SimpleTypeMarker @@ -164,20 +168,27 @@ object NewCommonSuperTypeCalculator { ): SimpleTypeMarker { if (types.size == 1) return types.single() - val nonTypeVariables = types.filter { !isTypeVariable(it) } + val nonTypeVariables = types.filter { !it.isStubTypeForVariableInSubtyping() && !isCapturedStubTypeForVariableInSubtyping(it) } if (nonTypeVariables.size == 1) return nonTypeVariables.single() assert(nonTypeVariables.isNotEmpty()) { "There should be at least one non-stub type to compute common supertype but there are: $types" } - val stubTypeVariables = types.filter { isStubTypeVariable(it) } - val nonStubTypeVariables = types.filter { !isStubTypeVariable(it) } + val nonStubTypeVariables = types.filter { !it.isStubType() } val areAllNonStubTypesNothing = nonStubTypeVariables.isNotEmpty() && nonStubTypeVariables.all { it.isNothing() } if (nonStubTypeVariables.size == 1 && !areAllNonStubTypesNothing) return nonStubTypeVariables.single() if (nonStubTypeVariables.isEmpty() || areAllNonStubTypesNothing) { - return uniquify(stubTypeVariables, contextStubTypesNotEqual).singleOrNull() ?: nullableAnyType() + val stubTypeVariables = types.filter { it.isStubType() } + val uniqueStubTypes = + stubTypeVariables.distinctBy { it.asDefinitelyNotNullType()?.original()?.typeConstructor() ?: it.typeConstructor() } + + if (uniqueStubTypes.size > 1) return nullableAnyType() + + if (stubTypeVariables.none { it.isDefinitelyNotNullType() }) { + return uniquify(stubTypeVariables.ifEmpty { types }, contextStubTypesNotEqual).singleOrNull() ?: return nullableAnyType() + } } val uniqueTypes = uniquify(nonTypeVariables, contextStubTypesNotEqual) @@ -192,16 +203,6 @@ object NewCommonSuperTypeCalculator { return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth, contextStubTypesEqualToAnything) } - private fun TypeSystemCommonSuperTypesContext.isStubTypeVariable(type: SimpleTypeMarker): Boolean { - return type.isStubType() || isStubCapturedTypeVariable(type) - } - - private fun TypeSystemCommonSuperTypesContext.isStubCapturedTypeVariable(type: SimpleTypeMarker): Boolean { - val projectedType = - type.asCapturedType()?.typeConstructor()?.projection()?.takeUnless { it.isStarProjection() }?.getType() ?: return false - return projectedType.asSimpleType()?.isStubType() == true - } - private fun TypeSystemCommonSuperTypesContext.isTypeVariable(type: SimpleTypeMarker): Boolean { return type.isStubTypeForVariableInSubtyping() || isCapturedTypeVariable(type) } diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/commonSuperTypeContravariant.kt b/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/commonSuperTypeContravariant.kt index e6e6afa951e..d135aff227d 100644 --- a/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/commonSuperTypeContravariant.kt +++ b/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/commonSuperTypeContravariant.kt @@ -34,16 +34,16 @@ fun select4(x: E?, y: In): E = x!! fun test() { val ret = build { emit("1") - select1(get(), getIn()) - select1(get(), Test.foo(getIn())) - select1(Test.foo(get()), Test.foo(getIn())) - select1(Test.foo(get()), getIn()) - select4(get(), getIn()) - select4(get(), Test.foo(getIn())) - select4(Test.foo(get()), Test.foo(getIn())) - select4(Test.foo(get()), getIn()) + select1(get(), getIn()) + select1(get(), Test.foo(getIn())) + select1(Test.foo(get()), Test.foo(getIn())) + select1(Test.foo(get()), getIn()) + select4(get(), getIn()) + select4(get(), Test.foo(getIn())) + select4(Test.foo(get()), Test.foo(getIn())) + select4(Test.foo(get()), getIn()) - select4(id(Test.foo(get())), getIn()) + select4(id(Test.foo(get())), getIn()) build2 { emit(1) @@ -55,30 +55,30 @@ fun test() { select2(get(), Test.foo(this@build.getIn())) select2(Test.foo(this@build.get()), Test.foo(getIn())) select2(Test.foo(get()), this@build.getIn()) - select3(this@build.get(), getIn()) - select3(get(), Test.foo(this@build.getIn())) + select3(this@build.get(), getIn()) + select3(get(), Test.foo(this@build.getIn())) select3(Test.foo(this@build.get()), Test.foo(getIn())) select3(Test.foo(get()), this@build.getIn()) - select4(this@build.get(), getIn()) - select4(get(), Test.foo(this@build.getIn())) + select4(this@build.get(), getIn()) + select4(get(), Test.foo(this@build.getIn())) select4(Test.foo(this@build.get()), Test.foo(getIn())) select4(Test.foo(get()), this@build.getIn()) - select4(id(Test.foo(this@build.get())), getIn()) + select4(id(Test.foo(this@build.get())), getIn()) "" } "" } val ret2 = build { emit(if (true) "" else null) - select2(get(), getIn()) - select2(get(), Test.foo(getIn())) - select2(Test.foo(get()), Test.foo(getIn())) - select2(Test.foo(get()), getIn()) - select3(get(), getIn()) - select3(get(), Test.foo(getIn())) - select3(Test.foo(get()), Test.foo(getIn())) - select3(Test.foo(get()), getIn()) + select2(get(), getIn()) + select2(get(), Test.foo(getIn())) + select2(Test.foo(get()), Test.foo(getIn())) + select2(Test.foo(get()), getIn()) + select3(get(), getIn()) + select3(get(), Test.foo(getIn())) + select3(Test.foo(get()), Test.foo(getIn())) + select3(Test.foo(get()), getIn()) "" } } diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index fdebabe90b9..5eb6d5b1b15 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -461,6 +461,17 @@ object AbstractTypeChecker { return null } + private fun TypeSystemContext.isStubTypeSubtypeOfAnother(a: SimpleTypeMarker, b: SimpleTypeMarker): Boolean { + val originalA = a.asDefinitelyNotNullType()?.original() ?: a + val originalB = b.asDefinitelyNotNullType()?.original() ?: b + + if (originalA.typeConstructor() !== originalB.typeConstructor()) return false + if (!a.isDefinitelyNotNullType() && b.isDefinitelyNotNullType()) return false + if (a.isMarkedNullable() && !b.isMarkedNullable()) return false + + return true // A!! == B!!, A? == B? or A == B + } + private fun checkSubtypeForSpecialCases( context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, @@ -478,10 +489,10 @@ object AbstractTypeChecker { ) } - if (subType.isStubType() && superType.isStubType()) - return subType.typeConstructor() === superType.typeConstructor() + if (subType.isStubTypeForBuilderInference() && superType.isStubTypeForBuilderInference()) + return isStubTypeSubtypeOfAnother(subType, superType) - if (subType.isStubType() || superType.isStubType() || subType.isStubTypeForVariableInSubtyping() || superType.isStubTypeForVariableInSubtyping()) + if (subType.isStubType() || superType.isStubType()) return context.isStubTypeEqualsToAnything // superType might be a definitely notNull type (see KT-42824) @@ -746,7 +757,7 @@ object AbstractNullabilityChecker { if (type.isNothing()) return true if (type.isMarkedNullable()) return false - if (context.isStubTypeEqualsToAnything && (type.isStubTypeForVariableInSubtyping() || type.isStubType())) return true + if (context.isStubTypeEqualsToAnything && type.isStubType()) return true return areEqualTypeConstructors(type.typeConstructor(), end) } diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index d21a33b55d0..cdf44cbd56e 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -300,6 +300,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext { fun SimpleTypeMarker.isStubType(): Boolean fun SimpleTypeMarker.isStubTypeForVariableInSubtyping(): Boolean + fun SimpleTypeMarker.isStubTypeForBuilderInference(): Boolean fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index f4fab61f076..4d3acf4d3e9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -236,6 +236,8 @@ internal class DescriptorRendererImpl( private fun StringBuilder.renderDefaultType(type: KotlinType) { this.renderAnnotations(type) + val originalTypeOfDefNotNullType = (type as? DefinitelyNotNullType)?.original + when { type.isError -> { if (type is UnresolvedType && presentableUnresolvedTypes) { @@ -249,7 +251,10 @@ internal class DescriptorRendererImpl( } append(renderTypeArguments(type.arguments)) } - type is StubTypeForBuilderInference -> append(type.originalTypeVariable.toString()) + type is StubTypeForBuilderInference -> + append(type.originalTypeVariable.toString()) + originalTypeOfDefNotNullType is StubTypeForBuilderInference -> + append(originalTypeOfDefNotNullType.originalTypeVariable.toString()) else -> renderTypeConstructorAndArguments(type) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt index 25961ed6c30..81c3701d2f9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt @@ -125,6 +125,8 @@ class DefinitelyNotNullType private constructor( ): Boolean { if (!type.canHaveUndefinedNullability()) return false + if (type is StubTypeForBuilderInference) return TypeUtils.isNullableType(type) + // Replacing `useCorrectedNullabilityForFlexibleTypeParameters` with true for all call-sites seems to be correct // But it seems that it should be a new feature: KT-28785 would be automatically fixed then // (see the tests org.jetbrains.kotlin.spec.checkers.DiagnosticsTestSpecGenerated.NotLinked.Dfa.Pos.test12/13) @@ -142,9 +144,10 @@ class DefinitelyNotNullType private constructor( } private fun UnwrappedType.canHaveUndefinedNullability(): Boolean = - constructor is NewTypeVariableConstructor || - constructor.declarationDescriptor is TypeParameterDescriptor || - this is NewCapturedType + constructor is NewTypeVariableConstructor + || constructor.declarationDescriptor is TypeParameterDescriptor + || this is NewCapturedType + || this is StubTypeForBuilderInference } @@ -159,13 +162,13 @@ class DefinitelyNotNullType private constructor( delegate.constructor.declarationDescriptor is TypeParameterDescriptor override fun substitutionResult(replacement: KotlinType): KotlinType = - replacement.unwrap().makeDefinitelyNotNullOrNotNull(useCorrectedNullabilityForTypeParameters) + replacement.unwrap().makeDefinitelyNotNullOrNotNull(useCorrectedNullabilityForTypeParameters) override fun replaceAnnotations(newAnnotations: Annotations): DefinitelyNotNullType = - DefinitelyNotNullType(delegate.replaceAnnotations(newAnnotations), useCorrectedNullabilityForTypeParameters) + DefinitelyNotNullType(delegate.replaceAnnotations(newAnnotations), useCorrectedNullabilityForTypeParameters) override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType = - if (newNullability) delegate.makeNullableAsSpecified(newNullability) else this + if (newNullability) delegate.makeNullableAsSpecified(newNullability) else this override fun toString(): String = "$delegate!!" diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 3357979b857..c99818f769b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -81,12 +81,20 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy override fun SimpleTypeMarker.isStubType(): Boolean { require(this is SimpleType, this::errorMessage) - return this is StubTypeForBuilderInference || this is StubTypeForProvideDelegateReceiver + return this is AbstractStubType || isDefNotNullStubType() } + private inline fun SimpleTypeMarker.isDefNotNullStubType() = + this is DefinitelyNotNullType && this.original is S + override fun SimpleTypeMarker.isStubTypeForVariableInSubtyping(): Boolean { require(this is SimpleType, this::errorMessage) - return this is StubTypeForTypeVariablesInSubtyping + return this is StubTypeForTypeVariablesInSubtyping || isDefNotNullStubType() + } + + override fun SimpleTypeMarker.isStubTypeForBuilderInference(): Boolean { + require(this is SimpleType, this::errorMessage) + return this is StubTypeForBuilderInference || isDefNotNullStubType() } override fun CapturedTypeMarker.lowerType(): KotlinTypeMarker? { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt index 6f289331677..462b075b874 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt @@ -170,6 +170,8 @@ object TypeIntersector { protected val UnwrappedType.resultNullability: ResultNullability get() = when { isMarkedNullable -> ACCEPT_NULL + this is DefinitelyNotNullType && this.original is StubTypeForBuilderInference -> NOT_NULL + this is StubTypeForBuilderInference -> UNKNOWN NullabilityChecker.isSubtypeOfAny(this) -> NOT_NULL else -> UNKNOWN }