From 23ed6c4a1f1b82b49c4d08743e52bf0f6e02fe83 Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Fri, 28 Feb 2020 12:46:36 +0300 Subject: [PATCH] [NI] Narrow nullability constraint check in incorporator This commit is a hotfix rather then proper solution. The source of the issue is that currently type variable fixation result may change due to fixation order alteration for variables with the same priority. For instance, having variables V1, V2, and proper types Type1, Type2, such that: V1 <: Type1 V1 <: V2 Type2 <: V2 both variables will be fixed either to Type1, if V1 will be fixed first, or to Type2 otherwise. Since this limitation cannot be easily overcome, the taken approach is to remove incedental constraint added after 2d5a0546 by restricting nullability constraint check to `Nothing?` constraints only, thus postponing problematic variable fixation. To clearify, additional constraint is correct and should cause no harm (in ideal world), but currently its presence changes fixation order. So without the restriction the previously used constraint from fixed outer variable is no longer available by the time problematic variable type is being selected. ^KT-37043 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 10 ++++++ .../components/ConstraintIncorporator.kt | 2 ++ .../inference/regressions/kt37043.fir.kt | 19 ++++++++++++ .../tests/inference/regressions/kt37043.kt | 19 ++++++++++++ .../tests/inference/regressions/kt37043.txt | 15 +++++++++ .../inference/regressions/kt37043_2.fir.kt | 31 +++++++++++++++++++ .../tests/inference/regressions/kt37043_2.kt | 31 +++++++++++++++++++ .../tests/inference/regressions/kt37043_2.txt | 10 ++++++ .../diagnostics/tests/j+k/matchers.fir.kt | 2 +- .../testsWithStdLib/inference/kt11266.kt | 2 +- .../testsWithStdLib/inference/kt11266.ni.txt | 2 +- .../checkers/DiagnosticsTestGenerated.java | 10 ++++++ .../DiagnosticsUsingJavacTestGenerated.java | 10 ++++++ 13 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37043.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37043.kt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37043.txt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.txt diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 0106735d7d8..620beb7814f 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -11345,6 +11345,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/regressions/kt36342_2.kt"); } + @TestMetadata("kt37043.kt") + public void testKt37043() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043.kt"); + } + + @TestMetadata("kt37043_2.kt") + public void testKt37043_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt"); + } + @TestMetadata("kt4420.kt") public void testKt4420() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt4420.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt index aaeef1e624a..20c929292ec 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt @@ -203,6 +203,8 @@ class ConstraintIncorporator( otherConstraint: KotlinTypeMarker, kind: ConstraintKind ): Boolean { + if (trivialConstraintTypeInferenceOracle.isSuitableResultedType(newConstraint)) return false + val otherConstraintCanAddNullabilityToNewOne = !newConstraint.isNullableType() && otherConstraint.isNullableType() && kind == ConstraintKind.LOWER val newConstraintCanAddNullabilityToOtherOne = diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37043.fir.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt37043.fir.kt new file mode 100644 index 00000000000..cda9701b1f8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37043.fir.kt @@ -0,0 +1,19 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE +// FILE: Test.java + +class Test { + static Number[] flexibleNumbers() { + return null; + } +} + +// FILE: main.kt + +fun foo(x: Array): T = x[0] + +inline fun materializeArray(): Array = null as Array + +fun main() { + val y = foo(Test.flexibleNumbers() ?: materializeArray()) // Any? in NI, Number! in OI (T of `materializeArray` is inferred to Any?) +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37043.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt37043.kt new file mode 100644 index 00000000000..cda9701b1f8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37043.kt @@ -0,0 +1,19 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE +// FILE: Test.java + +class Test { + static Number[] flexibleNumbers() { + return null; + } +} + +// FILE: main.kt + +fun foo(x: Array): T = x[0] + +inline fun materializeArray(): Array = null as Array + +fun main() { + val y = foo(Test.flexibleNumbers() ?: materializeArray()) // Any? in NI, Number! in OI (T of `materializeArray` is inferred to Any?) +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37043.txt b/compiler/testData/diagnostics/tests/inference/regressions/kt37043.txt new file mode 100644 index 00000000000..b3f15139433 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37043.txt @@ -0,0 +1,15 @@ +package + +public fun foo(/*0*/ x: kotlin.Array): T +public fun main(): kotlin.Unit +public inline fun materializeArray(): kotlin.Array + +public/*package*/ open class Test { + public/*package*/ constructor Test() + 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/*package*/ open fun flexibleNumbers(): kotlin.Array<(out) kotlin.Number!>! +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.fir.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.fir.kt new file mode 100644 index 00000000000..ae288a9e25a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.fir.kt @@ -0,0 +1,31 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -USELESS_ELVIS + +fun first(x: Array): T = TODO() +fun elvis(first: E?, second: E): E = TODO() + +inline fun materializeArray(): Array = TODO() + +fun nullableNumbers(): Array = TODO() +fun notNullableNumbers(): Array = TODO() +fun nullableNumbersNullableArray(): Array? = TODO() +fun notNullableNumbersNullableArray(): Array? = TODO() + +fun main() { + val number1 = first(elvis(notNullableNumbers(), materializeArray())) + val number2 = first(elvis(notNullableNumbersNullableArray(), materializeArray())) + val number3 = first(notNullableNumbers() ?: materializeArray()) + val number4 = first(notNullableNumbersNullableArray() ?: materializeArray()) + val nullableNumber1 = first(elvis(nullableNumbers(), materializeArray())) + val nullableNumber2 = first(elvis(nullableNumbersNullableArray(), materializeArray())) + val nullableNumber3 = first(nullableNumbers() ?: materializeArray()) + val nullableNumber4 = first(nullableNumbersNullableArray() ?: materializeArray()) + + number1 + number2 + number3 + number4 + nullableNumber1 + nullableNumber2 + nullableNumber3 + nullableNumber4 +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt new file mode 100644 index 00000000000..d26bba03c88 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt @@ -0,0 +1,31 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -USELESS_ELVIS + +fun first(x: Array): T = TODO() +fun elvis(first: E?, second: E): E = TODO() + +inline fun materializeArray(): Array = TODO() + +fun nullableNumbers(): Array = TODO() +fun notNullableNumbers(): Array = TODO() +fun nullableNumbersNullableArray(): Array? = TODO() +fun notNullableNumbersNullableArray(): Array? = TODO() + +fun main() { + val number1 = first(elvis(notNullableNumbers(), materializeArray())) + val number2 = first(elvis(notNullableNumbersNullableArray(), materializeArray())) + val number3 = first(notNullableNumbers() ?: materializeArray()) + val number4 = first(notNullableNumbersNullableArray() ?: materializeArray()) + val nullableNumber1 = first(elvis(nullableNumbers(), materializeArray())) + val nullableNumber2 = first(elvis(nullableNumbersNullableArray(), materializeArray())) + val nullableNumber3 = first(nullableNumbers() ?: materializeArray()) + val nullableNumber4 = first(nullableNumbersNullableArray() ?: materializeArray()) + + number1 + number2 + number3 + number4 + nullableNumber1 + nullableNumber2 + nullableNumber3 + nullableNumber4 +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.txt b/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.txt new file mode 100644 index 00000000000..2b883c7a9ce --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.txt @@ -0,0 +1,10 @@ +package + +public fun elvis(/*0*/ first: E?, /*1*/ second: E): E +public fun first(/*0*/ x: kotlin.Array): T +public fun main(): kotlin.Unit +public inline fun materializeArray(): kotlin.Array +public fun notNullableNumbers(): kotlin.Array +public fun notNullableNumbersNullableArray(): kotlin.Array? +public fun nullableNumbers(): kotlin.Array +public fun nullableNumbersNullableArray(): kotlin.Array? diff --git a/compiler/testData/diagnostics/tests/j+k/matchers.fir.kt b/compiler/testData/diagnostics/tests/j+k/matchers.fir.kt index 4c2bcb72eef..6d65c7863e9 100644 --- a/compiler/testData/diagnostics/tests/j+k/matchers.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/matchers.fir.kt @@ -14,5 +14,5 @@ public class Matcher { // FILE: main.kt fun test(x: List) { - Assert.assertThat(x, Matcher.hasItem("abc")) + Assert.assertThat(x, Matcher.hasItem("abc")) } diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.kt index ba3299f2b20..218fb33e0e4 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.kt @@ -1,4 +1,4 @@ // !WITH_NEW_INFERENCE // NI_EXPECTED_FILE -fun foo(first: Array, second: Array) = Pair(first.toCollection(), second.toCollection()) \ No newline at end of file +fun foo(first: Array, second: Array) = Pair(first.toCollection(), second.toCollection()) \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.ni.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.ni.txt index 71d97fe0ee3..e1f0a5b5c7b 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.ni.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/kt11266.ni.txt @@ -1,3 +1,3 @@ package -public fun foo(/*0*/ first: kotlin.Array, /*1*/ second: kotlin.Array): kotlin.Pair, kotlin.collections.MutableCollection> +public fun foo(/*0*/ first: kotlin.Array, /*1*/ second: kotlin.Array): [ERROR : Error function type] diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index ecc1aa61a08..b7b924b69e6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -11352,6 +11352,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/inference/regressions/kt36342_2.kt"); } + @TestMetadata("kt37043.kt") + public void testKt37043() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043.kt"); + } + + @TestMetadata("kt37043_2.kt") + public void testKt37043_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt"); + } + @TestMetadata("kt4420.kt") public void testKt4420() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt4420.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index e7711db9e30..59132defe83 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -11347,6 +11347,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/regressions/kt36342_2.kt"); } + @TestMetadata("kt37043.kt") + public void testKt37043() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043.kt"); + } + + @TestMetadata("kt37043_2.kt") + public void testKt37043_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt"); + } + @TestMetadata("kt4420.kt") public void testKt4420() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt4420.kt");