[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
This commit is contained in:
Pavel Kirpichenkov
2020-02-28 12:46:36 +03:00
parent ec01893237
commit 23ed6c4a1f
13 changed files with 160 additions and 3 deletions
@@ -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");
@@ -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 =
@@ -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 <T> foo(x: Array<out T>): T = x[0]
inline fun <reified T> materializeArray(): Array<T> = null as Array<T>
fun main() {
val y = foo(Test.flexibleNumbers() ?: materializeArray()) // Any? in NI, Number! in OI (T of `materializeArray` is inferred to Any?)
}
@@ -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 <T> foo(x: Array<out T>): T = x[0]
inline fun <reified T> materializeArray(): Array<T> = null as Array<T>
fun main() {
val y = foo(Test.flexibleNumbers() ?: materializeArray()) // Any? in NI, Number! in OI (T of `materializeArray` is inferred to Any?)
}
@@ -0,0 +1,15 @@
package
public fun </*0*/ T> foo(/*0*/ x: kotlin.Array<out T>): T
public fun main(): kotlin.Unit
public inline fun </*0*/ reified T> materializeArray(): kotlin.Array<T>
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!>!
}
@@ -0,0 +1,31 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -USELESS_ELVIS
fun <T> first(x: Array<out T>): T = TODO()
fun <E> elvis(first: E?, second: E): E = TODO()
inline fun <reified M> materializeArray(): Array<M> = TODO()
fun nullableNumbers(): Array<Number?> = TODO()
fun notNullableNumbers(): Array<Number> = TODO()
fun nullableNumbersNullableArray(): Array<Number?>? = TODO()
fun notNullableNumbersNullableArray(): Array<Number>? = 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
}
@@ -0,0 +1,31 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -USELESS_ELVIS
fun <T> first(x: Array<out T>): T = TODO()
fun <E> elvis(first: E?, second: E): E = TODO()
inline fun <reified M> materializeArray(): Array<M> = TODO()
fun nullableNumbers(): Array<Number?> = TODO()
fun notNullableNumbers(): Array<Number> = TODO()
fun nullableNumbersNullableArray(): Array<Number?>? = TODO()
fun notNullableNumbersNullableArray(): Array<Number>? = 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())
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number")!>number1<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number")!>number2<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number")!>number3<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number")!>number4<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumber1<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumber2<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumber3<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumber4<!>
}
@@ -0,0 +1,10 @@
package
public fun </*0*/ E> elvis(/*0*/ first: E?, /*1*/ second: E): E
public fun </*0*/ T> first(/*0*/ x: kotlin.Array<out T>): T
public fun main(): kotlin.Unit
public inline fun </*0*/ reified M> materializeArray(): kotlin.Array<M>
public fun notNullableNumbers(): kotlin.Array<kotlin.Number>
public fun notNullableNumbersNullableArray(): kotlin.Array<kotlin.Number>?
public fun nullableNumbers(): kotlin.Array<kotlin.Number?>
public fun nullableNumbersNullableArray(): kotlin.Array<kotlin.Number?>?
+1 -1
View File
@@ -14,5 +14,5 @@ public class Matcher<T> {
// FILE: main.kt
fun test(x: List<String>) {
Assert.<!INAPPLICABLE_CANDIDATE!>assertThat<!>(x, Matcher.hasItem("abc"))
Assert.assertThat(x, Matcher.hasItem("abc"))
}
@@ -1,4 +1,4 @@
// !WITH_NEW_INFERENCE
// NI_EXPECTED_FILE
fun foo(first: Array<Any?>, second: Array<Any?>) = Pair(first.toCollection(<!NO_VALUE_FOR_PARAMETER!>)<!>, second.toCollection(<!NO_VALUE_FOR_PARAMETER!>)<!>)
fun foo(first: Array<Any?>, second: Array<Any?>) = <!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>Pair<!>(first.<!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>toCollection<!>(<!NO_VALUE_FOR_PARAMETER!>)<!>, second.<!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>toCollection<!>(<!NO_VALUE_FOR_PARAMETER!>)<!>)
@@ -1,3 +1,3 @@
package
public fun foo(/*0*/ first: kotlin.Array<kotlin.Any?>, /*1*/ second: kotlin.Array<kotlin.Any?>): kotlin.Pair<kotlin.collections.MutableCollection<in kotlin.Any?>, kotlin.collections.MutableCollection<in kotlin.Any?>>
public fun foo(/*0*/ first: kotlin.Array<kotlin.Any?>, /*1*/ second: kotlin.Array<kotlin.Any?>): [ERROR : Error function type]
@@ -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");
@@ -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");