diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index db02ff5c048..ac18f925256 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -284,6 +284,7 @@ public interface Errors { SimpleDiagnosticFactory ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR); SimpleDiagnosticFactory NULLABLE_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, NULLABLE_TYPE); SimpleDiagnosticFactory REDUNDANT_NULLABLE = SimpleDiagnosticFactory.create(WARNING, NULLABLE_TYPE); + DiagnosticFactory1 BASE_WITH_NULLABLE_UPPER_BOUND = DiagnosticFactory1.create(WARNING, NULLABLE_TYPE); DiagnosticFactory1 UNSAFE_CALL = DiagnosticFactory1.create(ERROR); SimpleDiagnosticFactory AMBIGUOUS_LABEL = SimpleDiagnosticFactory.create(ERROR); DiagnosticFactory1 UNSUPPORTED = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index 1ad2c160b3c..8c08c4b0bee 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -307,6 +307,9 @@ public class DefaultErrorMessages { MAP.put(ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR, "Anonymous initializers are only allowed in the presence of a primary constructor"); MAP.put(NULLABLE_SUPERTYPE, "A supertype cannot be nullable"); MAP.put(REDUNDANT_NULLABLE, "Redundant '?'"); + MAP.put(BASE_WITH_NULLABLE_UPPER_BOUND, "''{0}'' has a nullable upper bound. " + + "This means that a value of this type may be null. " + + "Using ''{0}?'' is likely to mislead the reader", RENDER_TYPE); MAP.put(UNSAFE_CALL, "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}", RENDER_TYPE); MAP.put(AMBIGUOUS_LABEL, "Ambiguous label"); MAP.put(UNSUPPORTED, "Unsupported [{0}]", TO_STRING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 5bf1197ff91..056cd6a76bf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -178,6 +178,9 @@ public class TypeResolver { if (baseType.isNullable()) { trace.report(REDUNDANT_NULLABLE.on(nullableType)); } + else if (TypeUtils.hasNullableSuperType(baseType)) { + trace.report(BASE_WITH_NULLABLE_UPPER_BOUND.on(nullableType, baseType)); + } result[0] = TypeUtils.makeNullable(baseType); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index 753776bb9c7..32f50275153 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -385,6 +385,15 @@ public class TypeUtils { return false; } + public static boolean hasNullableSuperType(@NotNull JetType type) { + for (JetType supertype : getAllSupertypes(type)) { + if (supertype.isNullable()) { + return true; + } + } + return false; + } + public static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) { DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor1 == null) return false; // No class, classes are not equal diff --git a/compiler/testData/diagnostics/tests/checkArguments/SpreadVarargs.kt b/compiler/testData/diagnostics/tests/checkArguments/SpreadVarargs.kt index ab24181a58c..b06a3a34296 100644 --- a/compiler/testData/diagnostics/tests/checkArguments/SpreadVarargs.kt +++ b/compiler/testData/diagnostics/tests/checkArguments/SpreadVarargs.kt @@ -86,6 +86,6 @@ fun joinG(x : Int, vararg a : T) : String { return b.toString() } -fun joinT(x : Int, vararg a : T) : T? { +fun joinT(x : Int, vararg a : T) : T? { return null } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/incompleteCode/incompleteAssignment.kt b/compiler/testData/diagnostics/tests/incompleteCode/incompleteAssignment.kt index 0c45eac6f7e..0f5df3b436b 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/incompleteAssignment.kt +++ b/compiler/testData/diagnostics/tests/incompleteCode/incompleteAssignment.kt @@ -20,7 +20,7 @@ fun test(expectedSum : Int, vararg data : Int) { assertEquals(actualSum, expectedSum, "\ndata = ${Arrays.toString(data)}\n" + "sum(data) = ${actualSum}, but must be $expectedSum ") } -fun assertEquals(actual : T?, expected : T?, message : Any? = null) { +fun assertEquals(actual : T?, expected : T?, message : Any? = null) { if (actual != expected) { if (message == null) throw AssertionError() diff --git a/compiler/testData/diagnostics/tests/inference/NoInferenceFromDeclaredBounds.kt b/compiler/testData/diagnostics/tests/inference/NoInferenceFromDeclaredBounds.kt index 63362ef865e..0b954db9d16 100644 --- a/compiler/testData/diagnostics/tests/inference/NoInferenceFromDeclaredBounds.kt +++ b/compiler/testData/diagnostics/tests/inference/NoInferenceFromDeclaredBounds.kt @@ -1,4 +1,4 @@ -fun fooT22() : T? { +fun fooT22() : T? { return null } diff --git a/compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt b/compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt index a2b71f068af..b20162b20d9 100644 --- a/compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt +++ b/compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt @@ -1,10 +1,10 @@ package d -fun joinT(x: Int, vararg a: T): T? { +fun joinT(x: Int, vararg a: T): T? { return null } -fun joinT(x: Any, y: T): T? { +fun joinT(x: Any, y: T): T? { return null } diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt2286.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt2286.kt index 545c9ac68a3..c39cd683f35 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt2286.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt2286.kt @@ -24,4 +24,4 @@ abstract class Buggy { } //from library -fun Iterable.find(predicate: (T) -> Boolean) : T? {} \ No newline at end of file +fun Iterable.find(predicate: (T) -> Boolean) : T? {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt2505.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt2505.kt index b3c9fdfe9b8..8fce2b698a7 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt2505.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt2505.kt @@ -6,8 +6,8 @@ trait MyType {} class MyClass : MyType {} public open class HttpResponse() { - public open fun parseAs(dataClass : MyClass) : T? { - return null + public open fun parseAs(dataClass : MyClass) : T { + throw Exception() } public open fun parseAs(dataType : MyType) : Any? { return null @@ -16,5 +16,5 @@ public open class HttpResponse() { fun test (httpResponse: HttpResponse, rtype: MyClass) { val res = httpResponse.parseAs( rtype ) - res : R? //type mismatch: required R?, found T? + res : R //type mismatch: required R, found T } diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt702.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt702.kt index 88f8fcf843c..3934c5c4235 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt702.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt702.kt @@ -6,7 +6,7 @@ fun getJavaClass() : java.lang.Class { (throwable : Throwable?, declaredType : Class?) : Unit { + public fun propagateIfInstanceOf(throwable : Throwable?, declaredType : Class?>?) : Unit { if (((throwable != null) && declaredType?.isInstance(throwable)!!)) { throw declaredType?.cast(throwable)!! diff --git a/compiler/testData/diagnostics/tests/inference/varargs/varargsAndPair.kt b/compiler/testData/diagnostics/tests/inference/varargs/varargsAndPair.kt index 9d294ae34c7..681769e5c52 100644 --- a/compiler/testData/diagnostics/tests/inference/varargs/varargsAndPair.kt +++ b/compiler/testData/diagnostics/tests/inference/varargs/varargsAndPair.kt @@ -1,4 +1,4 @@ -fun foo(vararg ts: T): T? = null +fun foo(vararg ts: T): T? = null class Pair(a: A) diff --git a/compiler/testData/diagnostics/tests/kt53.kt b/compiler/testData/diagnostics/tests/kt53.kt index b1e33a7f1e9..0c9da0867c0 100644 --- a/compiler/testData/diagnostics/tests/kt53.kt +++ b/compiler/testData/diagnostics/tests/kt53.kt @@ -1,4 +1,4 @@ -val T.foo : E? +val T.foo : E? get() = null fun test(): Int? { diff --git a/compiler/testData/diagnostics/tests/nullableTypes/baseWithNullableUpperBound.kt b/compiler/testData/diagnostics/tests/nullableTypes/baseWithNullableUpperBound.kt new file mode 100644 index 00000000000..3772081bec2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/nullableTypes/baseWithNullableUpperBound.kt @@ -0,0 +1,24 @@ +fun nonMisleadingNullable( + nn: NN?, + nnn: NNN? +) {} + +fun twoBounds( + tb: TWO_BOUNDS? + +) where TWO_BOUNDS : NN {} + +fun misleadingNullableSimple( + t: T?, + t2: T?, + n: N?, + ind: INDIRECT? +) {} + +fun misleadingNullableMultiBound( + fb: FIRST_BOUND?, + sb: SECOND_BOUND? +) where FIRST_BOUND: Any, SECOND_BOUND: Any? { +} + +fun interactionWithRedundant(t: T??) {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt26.kt b/compiler/testData/diagnostics/tests/regressions/kt26.kt index d7ab1776b1a..c1557c3de55 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt26.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt26.kt @@ -7,6 +7,6 @@ import html.* // Must not be an error package html -abstract class Factory { +abstract class Factory { fun create() : T? = null } diff --git a/compiler/testData/diagnostics/tests/regressions/kt312.kt b/compiler/testData/diagnostics/tests/regressions/kt312.kt index 89085fbc485..783cbfc6bec 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt312.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt312.kt @@ -1,6 +1,6 @@ // KT-312 Nullability problem when a nullable version of a generic type is returned -fun Array.safeGet(index : Int) : T? { +fun Array.safeGet(index : Int) : T? { return if (index < size) this[index] else null } diff --git a/compiler/testData/diagnostics/tests/regressions/kt701.kt b/compiler/testData/diagnostics/tests/regressions/kt701.kt index beccf81e97a..272e865bc86 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt701.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt701.kt @@ -3,7 +3,7 @@ fun getJavaClass() : java.lang.Class { return "" as public class Throwables() { class object { - public fun propagateIfInstanceOf(throwable : Throwable?, declaredType : Class?) { + public fun propagateIfInstanceOf(throwable : Throwable?, declaredType : Class?>?) { if (((throwable != null) && declaredType?.isInstance(throwable)!!)) { throw declaredType?.cast(throwable)!! diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 22a5d648e1b..c2544192bb2 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -15,22 +15,19 @@ */ package org.jetbrains.jet.checkers; -import junit.framework.Assert; import junit.framework.Test; import junit.framework.TestSuite; - -import java.io.File; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.TestMetadata; -import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve; +import java.io.File; /** This class is generated by {@link org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve}. DO NOT MODIFY MANUALLY */ @InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class}) public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve { @TestMetadata("compiler/testData/diagnostics/tests") - @InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Scopes.class, Tests.Shadowing.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Tuples.class, Tests.Varargs.class}) + @InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Scopes.class, Tests.Shadowing.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Tuples.class, Tests.Varargs.class}) public static class Tests extends AbstractDiagnosticsTestWithEagerResolve { @TestMetadata("Abstract.kt") public void testAbstract() throws Exception { @@ -2294,6 +2291,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve", new File("compiler/testData/diagnostics/tests/nullableTypes"), "kt", true); } + @TestMetadata("baseWithNullableUpperBound.kt") + public void testBaseWithNullableUpperBound() throws Exception { + doTest("compiler/testData/diagnostics/tests/nullableTypes/baseWithNullableUpperBound.kt"); + } + @TestMetadata("redundantNullable.kt") public void testRedundantNullable() throws Exception { doTest("compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt"); @@ -3541,6 +3543,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage suite.addTest(Jdk_annotations.innerSuite()); suite.addTestSuite(Library.class); suite.addTestSuite(NullabilityAndAutoCasts.class); + suite.addTestSuite(NullableTypes.class); suite.addTestSuite(Objects.class); suite.addTestSuite(OperatorsOverloading.class); suite.addTestSuite(Overload.class);