fixed bug in constraint system
For parameter type T constraint T? <: Int? should NOT transform to T <: Int, it should be T <: Int? equality constraint T? = Int? should transform to T <: Int? && T >: Int
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND
|
||||||
|
class TypeOf<T>(t: T)
|
||||||
|
|
||||||
|
trait A<T>
|
||||||
|
|
||||||
|
fun <T> foo(a: A<T>, aN: A<T?>): T = throw Exception("$a $aN")
|
||||||
|
|
||||||
|
fun <T> doA(a: A<T>): T = throw Exception("$a")
|
||||||
|
|
||||||
|
fun test(a: A<Int>, aN: A<Int?>) {
|
||||||
|
val aa = doA(aN)
|
||||||
|
TypeOf(aa): TypeOf<Int?>
|
||||||
|
|
||||||
|
val nullable = foo(aN, aN)
|
||||||
|
//T = Int?, T? = Int? => T = Int?
|
||||||
|
TypeOf(nullable): TypeOf<Int?>
|
||||||
|
|
||||||
|
val notNullable = foo(a, aN)
|
||||||
|
//T = Int, T? = Int? => T = Int
|
||||||
|
TypeOf(notNullable): TypeOf<Int>
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
class TypeOf<T>(t: T)
|
||||||
|
|
||||||
|
trait A<T>
|
||||||
|
|
||||||
|
trait In<in T>
|
||||||
|
|
||||||
|
trait Out<out T>
|
||||||
|
|
||||||
|
fun <T: Any> doT(t: T?): T = throw Exception("$t")
|
||||||
|
fun <T: Any> doOut(o: Out<T?>): T { throw Exception("$o") }
|
||||||
|
fun <T: Any> doIn(i: In<T?>) { throw Exception("$i") }
|
||||||
|
fun <T: Any> doA(i: A<T?>) { throw Exception("$i") }
|
||||||
|
|
||||||
|
fun test(out: Out<Int>, i: In<Int>, inv: A<Int>) {
|
||||||
|
// T? >: Int => T = Int
|
||||||
|
doT(1)
|
||||||
|
val r = doOut(out)
|
||||||
|
TypeOf(r): TypeOf<Int>
|
||||||
|
|
||||||
|
// T? <: Int => error
|
||||||
|
doIn(<!TYPE_MISMATCH!>i<!>)
|
||||||
|
|
||||||
|
// T? >: Int => error
|
||||||
|
doA(<!TYPE_MISMATCH!>inv<!>)
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND
|
||||||
|
class TypeOf<T>(t: T)
|
||||||
|
|
||||||
|
trait A<T>
|
||||||
|
|
||||||
|
trait Out<out T>
|
||||||
|
|
||||||
|
fun <T> foo(a: A<T>, o: Out<T?>): T = throw Exception("$a $o")
|
||||||
|
|
||||||
|
fun <T> doOut(o: Out<T?>): T = throw Exception("$o")
|
||||||
|
|
||||||
|
fun test(a: A<Int>, aN: A<Int?>, o: Out<Int?>) {
|
||||||
|
val out = doOut(o)
|
||||||
|
//T? >: Int? => T >: Int
|
||||||
|
TypeOf(out): TypeOf<Int>
|
||||||
|
|
||||||
|
val nullable = foo(aN, o)
|
||||||
|
//T = Int?, T? >: Int? => T = Int?
|
||||||
|
TypeOf(nullable): TypeOf<Int?>
|
||||||
|
|
||||||
|
val notNullable = foo(a, o)
|
||||||
|
//T = Int, T? >: Int? => T = Int
|
||||||
|
TypeOf(notNullable): TypeOf<Int>
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND
|
||||||
|
class TypeOf<T>(t: T)
|
||||||
|
|
||||||
|
trait A<T>
|
||||||
|
|
||||||
|
trait In<in T>
|
||||||
|
|
||||||
|
fun <T> foo(a: A<T>, i: In<T>): T = throw Exception("$a $i")
|
||||||
|
|
||||||
|
fun <T> doIn(i: In<T?>): T = throw Exception("$i")
|
||||||
|
|
||||||
|
fun test(a: A<Int>, aN: A<Int?>, i: In<Int?>) {
|
||||||
|
val _in = doIn(i)
|
||||||
|
//T? <: Int? => T <: Int?
|
||||||
|
TypeOf(_in): TypeOf<Int?>
|
||||||
|
|
||||||
|
val notNullable = foo(a, i)
|
||||||
|
//T = Int, T? <: Int? => T = Int
|
||||||
|
TypeOf(notNullable): TypeOf<Int>
|
||||||
|
|
||||||
|
val nullable = foo(aN, i)
|
||||||
|
//T = Int?, T? <: Int? => T = Int?
|
||||||
|
TypeOf(nullable): TypeOf<Int?>
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package o
|
||||||
|
|
||||||
|
fun foo(): String? {
|
||||||
|
return accept(JV<String?, Unit?>())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R, D> accept(<!UNUSED_PARAMETER!>v<!>: JV<R, D>): R<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!> = null
|
||||||
|
|
||||||
|
open class JV<R, D>()
|
||||||
@@ -3038,7 +3038,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/inference")
|
@TestMetadata("compiler/testData/diagnostics/tests/inference")
|
||||||
@InnerTestClasses({Inference.NestedCalls.class, Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.UpperBounds.class, Inference.Varargs.class})
|
@InnerTestClasses({Inference.Constraints.class, Inference.NestedCalls.class, Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.UpperBounds.class, Inference.Varargs.class})
|
||||||
public static class Inference extends AbstractDiagnosticsTestWithEagerResolve {
|
public static class Inference extends AbstractDiagnosticsTestWithEagerResolve {
|
||||||
public void testAllFilesPresentInInference() throws Exception {
|
public void testAllFilesPresentInInference() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
@@ -3154,6 +3154,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
doTest("compiler/testData/diagnostics/tests/inference/noInformationForParameter.kt");
|
doTest("compiler/testData/diagnostics/tests/inference/noInformationForParameter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullableUpperBound.kt")
|
||||||
|
public void testNullableUpperBound() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/inference/nullableUpperBound.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("opposite.kt")
|
@TestMetadata("opposite.kt")
|
||||||
public void testOpposite() throws Exception {
|
public void testOpposite() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/inference/opposite.kt");
|
doTest("compiler/testData/diagnostics/tests/inference/opposite.kt");
|
||||||
@@ -3179,6 +3184,34 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
doTest("compiler/testData/diagnostics/tests/inference/useFunctionLiteralsToInferType.kt");
|
doTest("compiler/testData/diagnostics/tests/inference/useFunctionLiteralsToInferType.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/tests/inference/constraints")
|
||||||
|
public static class Constraints extends AbstractDiagnosticsTestWithEagerResolve {
|
||||||
|
public void testAllFilesPresentInConstraints() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference/constraints"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("equalityConstraintOnNullableType.kt")
|
||||||
|
public void testEqualityConstraintOnNullableType() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("notNullConstraintOnNullableType.kt")
|
||||||
|
public void testNotNullConstraintOnNullableType() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/inference/constraints/notNullConstraintOnNullableType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("subtypeConstraintOnNullableType.kt")
|
||||||
|
public void testSubtypeConstraintOnNullableType() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/inference/constraints/subtypeConstraintOnNullableType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("supertypeConstraintOnNullableType.kt")
|
||||||
|
public void testSupertypeConstraintOnNullableType() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/inference/constraints/supertypeConstraintOnNullableType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/nestedCalls")
|
@TestMetadata("compiler/testData/diagnostics/tests/inference/nestedCalls")
|
||||||
public static class NestedCalls extends AbstractDiagnosticsTestWithEagerResolve {
|
public static class NestedCalls extends AbstractDiagnosticsTestWithEagerResolve {
|
||||||
public void testAllFilesPresentInNestedCalls() throws Exception {
|
public void testAllFilesPresentInNestedCalls() throws Exception {
|
||||||
@@ -3537,6 +3570,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
public static Test innerSuite() {
|
public static Test innerSuite() {
|
||||||
TestSuite suite = new TestSuite("Inference");
|
TestSuite suite = new TestSuite("Inference");
|
||||||
suite.addTestSuite(Inference.class);
|
suite.addTestSuite(Inference.class);
|
||||||
|
suite.addTestSuite(Constraints.class);
|
||||||
suite.addTestSuite(NestedCalls.class);
|
suite.addTestSuite(NestedCalls.class);
|
||||||
suite.addTestSuite(Regressions.class);
|
suite.addTestSuite(Regressions.class);
|
||||||
suite.addTestSuite(ReportingImprovements.class);
|
suite.addTestSuite(ReportingImprovements.class);
|
||||||
|
|||||||
+14
-4
@@ -336,11 +336,21 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
|
TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
|
||||||
assert typeConstraints != null : "constraint should be generated only for type variables";
|
assert typeConstraints != null : "constraint should be generated only for type variables";
|
||||||
|
|
||||||
if (parameterType.isNullable()) {
|
if (!parameterType.isNullable() || !constrainingType.isNullable()) {
|
||||||
// For parameter type T constraint T? <: Int? should transform to T <: Int
|
typeConstraints.addBound(boundKind, constrainingType);
|
||||||
constrainingType = TypeUtils.makeNotNullable(constrainingType);
|
return;
|
||||||
|
}
|
||||||
|
// For parameter type T:
|
||||||
|
// constraint T? = Int? should transform to T >: Int and T <: Int?
|
||||||
|
// constraint T? >: Int? should transform to T >: Int
|
||||||
|
JetType notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType);
|
||||||
|
if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) {
|
||||||
|
typeConstraints.addBound(LOWER_BOUND, notNullConstrainingType);
|
||||||
|
}
|
||||||
|
// constraint T? <: Int? should transform to T <: Int?
|
||||||
|
if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) {
|
||||||
|
typeConstraints.addBound(UPPER_BOUND, constrainingType);
|
||||||
}
|
}
|
||||||
typeConstraints.addBound(boundKind, constrainingType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processDeclaredBoundConstraints() {
|
public void processDeclaredBoundConstraints() {
|
||||||
|
|||||||
Reference in New Issue
Block a user