diff --git a/compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt b/compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt new file mode 100644 index 00000000000..4454c3f8fde --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt @@ -0,0 +1,21 @@ +// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND +class TypeOf(t: T) + +trait A + +fun foo(a: A, aN: A): T = throw Exception("$a $aN") + +fun doA(a: A): T = throw Exception("$a") + +fun test(a: A, aN: A) { + val aa = doA(aN) + TypeOf(aa): TypeOf + + val nullable = foo(aN, aN) + //T = Int?, T? = Int? => T = Int? + TypeOf(nullable): TypeOf + + val notNullable = foo(a, aN) + //T = Int, T? = Int? => T = Int + TypeOf(notNullable): TypeOf +} diff --git a/compiler/testData/diagnostics/tests/inference/constraints/notNullConstraintOnNullableType.kt b/compiler/testData/diagnostics/tests/inference/constraints/notNullConstraintOnNullableType.kt new file mode 100644 index 00000000000..af4c22b6ca5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/constraints/notNullConstraintOnNullableType.kt @@ -0,0 +1,25 @@ +class TypeOf(t: T) + +trait A + +trait In + +trait Out + +fun doT(t: T?): T = throw Exception("$t") +fun doOut(o: Out): T { throw Exception("$o") } +fun doIn(i: In) { throw Exception("$i") } +fun doA(i: A) { throw Exception("$i") } + +fun test(out: Out, i: In, inv: A) { + // T? >: Int => T = Int + doT(1) + val r = doOut(out) + TypeOf(r): TypeOf + + // T? <: Int => error + doIn(i) + + // T? >: Int => error + doA(inv) +} diff --git a/compiler/testData/diagnostics/tests/inference/constraints/subtypeConstraintOnNullableType.kt b/compiler/testData/diagnostics/tests/inference/constraints/subtypeConstraintOnNullableType.kt new file mode 100644 index 00000000000..de1d49a45eb --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/constraints/subtypeConstraintOnNullableType.kt @@ -0,0 +1,24 @@ +// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND +class TypeOf(t: T) + +trait A + +trait Out + +fun foo(a: A, o: Out): T = throw Exception("$a $o") + +fun doOut(o: Out): T = throw Exception("$o") + +fun test(a: A, aN: A, o: Out) { + val out = doOut(o) + //T? >: Int? => T >: Int + TypeOf(out): TypeOf + + val nullable = foo(aN, o) + //T = Int?, T? >: Int? => T = Int? + TypeOf(nullable): TypeOf + + val notNullable = foo(a, o) + //T = Int, T? >: Int? => T = Int + TypeOf(notNullable): TypeOf +} diff --git a/compiler/testData/diagnostics/tests/inference/constraints/supertypeConstraintOnNullableType.kt b/compiler/testData/diagnostics/tests/inference/constraints/supertypeConstraintOnNullableType.kt new file mode 100644 index 00000000000..9aacaca6268 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/constraints/supertypeConstraintOnNullableType.kt @@ -0,0 +1,24 @@ +// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND +class TypeOf(t: T) + +trait A + +trait In + +fun foo(a: A, i: In): T = throw Exception("$a $i") + +fun doIn(i: In): T = throw Exception("$i") + +fun test(a: A, aN: A, i: In) { + val _in = doIn(i) + //T? <: Int? => T <: Int? + TypeOf(_in): TypeOf + + val notNullable = foo(a, i) + //T = Int, T? <: Int? => T = Int + TypeOf(notNullable): TypeOf + + val nullable = foo(aN, i) + //T = Int?, T? <: Int? => T = Int? + TypeOf(nullable): TypeOf +} diff --git a/compiler/testData/diagnostics/tests/inference/nullableUpperBound.kt b/compiler/testData/diagnostics/tests/inference/nullableUpperBound.kt new file mode 100644 index 00000000000..358df6853b4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/nullableUpperBound.kt @@ -0,0 +1,9 @@ +package o + +fun foo(): String? { + return accept(JV()) +} + +fun accept(v: JV): R? = null + +open class JV() \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index c32e9754120..994b7a62c75 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3038,7 +3038,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } @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 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); @@ -3154,6 +3154,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage 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") public void testOpposite() throws Exception { 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"); } + @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") public static class NestedCalls extends AbstractDiagnosticsTestWithEagerResolve { public void testAllFilesPresentInNestedCalls() throws Exception { @@ -3537,6 +3570,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage public static Test innerSuite() { TestSuite suite = new TestSuite("Inference"); suite.addTestSuite(Inference.class); + suite.addTestSuite(Constraints.class); suite.addTestSuite(NestedCalls.class); suite.addTestSuite(Regressions.class); suite.addTestSuite(ReportingImprovements.class); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java index 0e6c1932a77..9423426ac42 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java @@ -336,11 +336,21 @@ public class ConstraintSystemImpl implements ConstraintSystem { TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType); assert typeConstraints != null : "constraint should be generated only for type variables"; - if (parameterType.isNullable()) { - // For parameter type T constraint T? <: Int? should transform to T <: Int - constrainingType = TypeUtils.makeNotNullable(constrainingType); + if (!parameterType.isNullable() || !constrainingType.isNullable()) { + typeConstraints.addBound(boundKind, 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() {