K2: Fix processing inference lower bound NullableType <: T & Any
Previously, it was led to plainly adding NullableType <: T constraint which silently led to successful call completion. What is suggested is just marking such initial constraint as unsuccessful. In K1, the error was reported just via additional type checking mechanism being run after call completion. ^KT-58665 Fixed
This commit is contained in:
committed by
Space Team
parent
7bc04e2c33
commit
0d070f8ba9
+12
@@ -15156,6 +15156,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nothingVsParameterBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableArgumentForDnn.kt")
|
||||
public void testNullableArgumentForDnn() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nullableArgumentForDnn.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableTypeArgumentWithNotNullUpperBound.kt")
|
||||
public void testNullableTypeArgumentWithNotNullUpperBound() throws Exception {
|
||||
@@ -19934,6 +19940,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/mutableIterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOf.kt")
|
||||
public void testNullForOptionalOf() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOrElse.kt")
|
||||
public void testNullForOptionalOrElse() throws Exception {
|
||||
|
||||
+12
@@ -15156,6 +15156,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nothingVsParameterBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableArgumentForDnn.kt")
|
||||
public void testNullableArgumentForDnn() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nullableArgumentForDnn.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableTypeArgumentWithNotNullUpperBound.kt")
|
||||
public void testNullableTypeArgumentWithNotNullUpperBound() throws Exception {
|
||||
@@ -19934,6 +19940,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/mutableIterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOf.kt")
|
||||
public void testNullForOptionalOf() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOrElse.kt")
|
||||
public void testNullForOptionalOrElse() throws Exception {
|
||||
|
||||
+12
@@ -15156,6 +15156,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nothingVsParameterBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableArgumentForDnn.kt")
|
||||
public void testNullableArgumentForDnn() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nullableArgumentForDnn.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableTypeArgumentWithNotNullUpperBound.kt")
|
||||
public void testNullableTypeArgumentWithNotNullUpperBound() throws Exception {
|
||||
@@ -19934,6 +19940,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/mutableIterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOf.kt")
|
||||
public void testNullForOptionalOf() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOrElse.kt")
|
||||
public void testNullForOptionalOrElse() throws Exception {
|
||||
|
||||
+12
@@ -15162,6 +15162,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nothingVsParameterBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableArgumentForDnn.kt")
|
||||
public void testNullableArgumentForDnn() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nullableArgumentForDnn.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableTypeArgumentWithNotNullUpperBound.kt")
|
||||
public void testNullableTypeArgumentWithNotNullUpperBound() throws Exception {
|
||||
@@ -19940,6 +19946,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/mutableIterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOf.kt")
|
||||
public void testNullForOptionalOf() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOrElse.kt")
|
||||
public void testNullForOptionalOrElse() throws Exception {
|
||||
|
||||
+39
-25
@@ -205,6 +205,13 @@ abstract class TypeCheckerStateForConstraintSystem(
|
||||
* (Foo & Any .. Bar) <: T -- (Foo!! .. Bar) <: T
|
||||
*
|
||||
* => (Foo..Bar) <: T! -- (Foo!! .. Bar) <: T
|
||||
*
|
||||
* T & Any
|
||||
*
|
||||
* Foo? <: T & Any => ERROR (for K2 only)
|
||||
*
|
||||
* Foo..Bar? <: T & Any => Foo..Bar? <: T
|
||||
* Foo <: T & Any => Foo <: T
|
||||
*/
|
||||
private fun simplifyLowerConstraint(
|
||||
typeVariable: KotlinTypeMarker,
|
||||
@@ -213,35 +220,41 @@ abstract class TypeCheckerStateForConstraintSystem(
|
||||
): Boolean = with(extensionTypeContext) {
|
||||
val lowerConstraint = when (typeVariable) {
|
||||
is SimpleTypeMarker ->
|
||||
/*
|
||||
* Foo <: T -- Foo <: T
|
||||
* Foo <: T? (T is contained in invariant or contravariant positions of a return type) -- Foo <: T
|
||||
* Example:
|
||||
* fun <T> foo(x: T?): Inv<T> {}
|
||||
* fun <K> main(z: K) { val x = foo(z) }
|
||||
* Foo <: T? (T isn't contained there) -- Foo!! <: T
|
||||
* Example:
|
||||
* fun <T> foo(x: T?) {}
|
||||
* fun <K> main(z: K) { foo(z) }
|
||||
*/
|
||||
if (typeVariable.isMarkedNullable()) {
|
||||
val typeVariableTypeConstructor = typeVariable.typeConstructor()
|
||||
val subTypeConstructor = subType.typeConstructor()
|
||||
val needToMakeDefNotNull = subTypeConstructor.isTypeVariable() ||
|
||||
typeVariableTypeConstructor !is TypeVariableTypeConstructorMarker ||
|
||||
!typeVariableTypeConstructor.isContainedInInvariantOrContravariantPositions()
|
||||
when {
|
||||
// Foo? (any type which cannot be used as dispatch receiver because of nullability) <: T & Any => ERROR (for K2 only)
|
||||
isK2 && typeVariable.isDefinitelyNotNullType()
|
||||
&& !AbstractNullabilityChecker.isSubtypeOfAny(extensionTypeContext, subType) -> return false
|
||||
/*
|
||||
* Foo <: T? (T is contained in invariant or contravariant positions of a return type) -- Foo <: T
|
||||
* Example:
|
||||
* fun <T> foo(x: T?): Inv<T> {}
|
||||
* fun <K> main(z: K) { val x = foo(z) }
|
||||
* Foo <: T? (T isn't contained there) -- Foo!! <: T
|
||||
* Example:
|
||||
* fun <T> foo(x: T?) {}
|
||||
* fun <K> main(z: K) { foo(z) }
|
||||
*/
|
||||
typeVariable.isMarkedNullable() -> {
|
||||
val typeVariableTypeConstructor = typeVariable.typeConstructor()
|
||||
val subTypeConstructor = subType.typeConstructor()
|
||||
val needToMakeDefNotNull = subTypeConstructor.isTypeVariable() ||
|
||||
typeVariableTypeConstructor !is TypeVariableTypeConstructorMarker ||
|
||||
!typeVariableTypeConstructor.isContainedInInvariantOrContravariantPositions()
|
||||
|
||||
val resultType = if (needToMakeDefNotNull) {
|
||||
subType.makeDefinitelyNotNullOrNotNull()
|
||||
} else {
|
||||
if (!isInferenceCompatibilityEnabled && subType is CapturedTypeMarker) {
|
||||
subType.withNotNullProjection()
|
||||
val resultType = if (needToMakeDefNotNull) {
|
||||
subType.makeDefinitelyNotNullOrNotNull()
|
||||
} else {
|
||||
subType.withNullability(false)
|
||||
if (!isInferenceCompatibilityEnabled && subType is CapturedTypeMarker) {
|
||||
subType.withNotNullProjection()
|
||||
} else {
|
||||
subType.withNullability(false)
|
||||
}
|
||||
}
|
||||
if (isInferenceCompatibilityEnabled && resultType is CapturedTypeMarker) resultType.withNotNullProjection() else resultType
|
||||
}
|
||||
if (isInferenceCompatibilityEnabled && resultType is CapturedTypeMarker) resultType.withNotNullProjection() else resultType
|
||||
} else subType
|
||||
// Foo <: T => Foo <: T
|
||||
else -> subType
|
||||
}
|
||||
|
||||
is FlexibleTypeMarker -> {
|
||||
assertFlexibleTypeVariable(typeVariable)
|
||||
@@ -298,6 +311,7 @@ abstract class TypeCheckerStateForConstraintSystem(
|
||||
* T! <: Foo <=> T <: Foo & Any..Foo?
|
||||
* T? <: Foo <=> T <: Foo && Nothing? <: Foo
|
||||
* T <: Foo -- leave as is
|
||||
* T & Any <: Foo <=> T <: Foo?
|
||||
*/
|
||||
private fun simplifyUpperConstraint(typeVariable: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean = with(extensionTypeContext) {
|
||||
val typeVariableLowerBound = typeVariable.lowerBoundIfFlexible()
|
||||
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun <T> foo(x: T, y: T & Any) = x!!
|
||||
|
||||
fun main() {
|
||||
foo<String>("", "").length
|
||||
foo<String>("", <!NULL_FOR_NONNULL_TYPE!>null<!>).length
|
||||
foo<String?>(null, "").length
|
||||
foo<String?>(null, null).length
|
||||
|
||||
foo("", "").length
|
||||
foo("", null).length
|
||||
foo(null, "").length
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun <T> foo(x: T, y: T & Any) = x!!
|
||||
|
||||
Vendored
+1
-1
@@ -28,6 +28,6 @@ fun <F> main(x: F, y: F, z: F, w: F, m: F) {
|
||||
w1.foo()
|
||||
w2.foo()
|
||||
|
||||
expectNN(m)
|
||||
expectNN(<!ARGUMENT_TYPE_MISMATCH!>m<!>)
|
||||
expectNN(m!!)
|
||||
}
|
||||
|
||||
Vendored
-14
@@ -1,14 +0,0 @@
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun <T> foo(x: T, y: T & Any): T & Any = x ?: y
|
||||
|
||||
fun main() {
|
||||
foo<String>("", "").length
|
||||
foo<String>("", <!NULL_FOR_NONNULL_TYPE!>null<!>).length
|
||||
foo<String?>(null, "").length
|
||||
foo<String?>(null, null).length
|
||||
|
||||
foo("", "").length
|
||||
foo("", null).length
|
||||
foo(null, "").length
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun <T> foo(x: T, y: T & Any): T & Any = x ?: y
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// ISSUE: KT-58665
|
||||
|
||||
fun <R, T : Any> use(x: String?, r: R, t: T) {
|
||||
foo(<!ARGUMENT_TYPE_MISMATCH!>x<!>)
|
||||
foo(<!ARGUMENT_TYPE_MISMATCH!>r<!>)
|
||||
foo(t)
|
||||
}
|
||||
|
||||
fun <W> foo(x: W & Any) {}
|
||||
@@ -0,0 +1,9 @@
|
||||
// ISSUE: KT-58665
|
||||
|
||||
fun <R, T : Any> use(x: String?, r: R, t: T) {
|
||||
foo(<!TYPE_MISMATCH!>x<!>)
|
||||
foo(<!TYPE_MISMATCH!>r<!>)
|
||||
foo(t)
|
||||
}
|
||||
|
||||
fun <W> foo(x: W & Any) {}
|
||||
@@ -0,0 +1,8 @@
|
||||
// ISSUE: KT-58665
|
||||
// FULL_JDK
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun use(x: String?) {
|
||||
Optional.of(<!ARGUMENT_TYPE_MISMATCH!>x<!>)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// ISSUE: KT-58665
|
||||
// FULL_JDK
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun use(x: String?) {
|
||||
Optional.of(<!TYPE_MISMATCH!>x<!>)
|
||||
}
|
||||
Vendored
+2
-2
@@ -21,8 +21,8 @@ fun <V> SLRUMap<V>.getOrPut(value: V, l: List<V>) {
|
||||
takeV(<!ARGUMENT_TYPE_MISMATCH!>value<!>)
|
||||
takeVList(<!ARGUMENT_TYPE_MISMATCH!>l<!>)
|
||||
|
||||
takeE(value)
|
||||
takeEList(l)
|
||||
takeE(<!ARGUMENT_TYPE_MISMATCH!>value<!>)
|
||||
takeEList(<!ARGUMENT_TYPE_MISMATCH!>l<!>)
|
||||
takeE(id(value))
|
||||
|
||||
if (value != null) {
|
||||
|
||||
Vendored
+2
-2
@@ -22,8 +22,8 @@ fun <V> SLRUMap<V>.getOrPut(value: V, l: List<V>) {
|
||||
takeV(<!ARGUMENT_TYPE_MISMATCH!>value<!>)
|
||||
takeVList(<!ARGUMENT_TYPE_MISMATCH!>l<!>)
|
||||
|
||||
takeE(value)
|
||||
takeEList(l)
|
||||
takeE(<!ARGUMENT_TYPE_MISMATCH!>value<!>)
|
||||
takeEList(<!ARGUMENT_TYPE_MISMATCH!>l<!>)
|
||||
takeE(id(value))
|
||||
|
||||
if (value != null) {
|
||||
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
// FILE: A.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class A {
|
||||
public static <T> void bar(@NotNull T x, T y) { }
|
||||
public static String platformString() { return null; }
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
A.bar(null, "")
|
||||
|
||||
A.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||
A.bar<String?>(null, "")
|
||||
A.bar(null, A.platformString())
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: A.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
Generated
+12
@@ -15162,6 +15162,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nothingVsParameterBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableArgumentForDnn.kt")
|
||||
public void testNullableArgumentForDnn() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/nullableArgumentForDnn.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableTypeArgumentWithNotNullUpperBound.kt")
|
||||
public void testNullableTypeArgumentWithNotNullUpperBound() throws Exception {
|
||||
@@ -19940,6 +19946,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/mutableIterator.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOf.kt")
|
||||
public void testNullForOptionalOf() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullForOptionalOrElse.kt")
|
||||
public void testNullForOptionalOrElse() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user